﻿#ifndef __INC_QGDRV_GL_RDH_H__
#define __INC_QGDRV_GL_RDH_H__

#ifdef _MSC_VER
#pragma once
#endif

#include "qgp/qgach.h"

//
#if _QG_USE_ANGLE || _SB_ANDROID_ || _SB_IOS_
#	define QG_OPENGL_ES2	1
#	include "qg_opengl_es2.h"
#elif _SB_WINDOWS_ || _SB_APPLE_ || _SB_LINUX_ || _SB_BSD_
#	define QG_OPENGL_V4		1
#	include "qg_opengl_v4.h"
#else
#	error unknown OpenGL version
#endif

#define QGGL_MAX_DRAWLAYOUT_ATTRIB		12

#include "qgdrv_gl_cq.h"

//////////////////////////////////////////////////////////////////////////
// OpenGL

class GLShader;
class GLLayout;
class GLBuffer;
class GLDepthBuffer;
class GLTexture;
class GLTextureMotion;
class GLTextureOff;

// 렌더러
class GLRdh : public qgRdh, public qbOpenGL
{
	KCH_SUBCLASS(GLRdh, qgRdh);

public:
	// 상태값
	struct Session
	{
		GLDhslProperty			dhsl_prop;
		GLRaszProperty			rasz_prop;
		GLBlndProperty			blnd_props[QGSGOFF_MAX_VALUE];

		kint					tex_active;
		GLTextureProperty		tex_props[QGSGTEX_MAX_VALUE];

		GLuint					shd_program;
		GLLayoutProperty		los_props[QGGL_MAX_DRAWLAYOUT_ATTRIB];

		GLuint					buf_array;
		GLuint					buf_element_array;
		GLuint					buf_pixel_unpack;

		bool					scis_enable;
		tpl::Rect				scis_rect;

		Session()
			: tex_active(-1)
			, shd_program(QGGL_INVALID_UINT)
			, buf_array(QGGL_INVALID_UINT), buf_element_array(QGGL_INVALID_UINT), buf_pixel_unpack(QGGL_INVALID_UINT)
			, scis_enable(false), scis_rect(0, 0, 0, 0)
		{
		}
	};

	//
	struct Pending
	{
		GLDhslProperty			dhsl_prop;
		GLRaszProperty			rasz_prop;
		GLBlndProperty			blnd_props[QGSGOFF_MAX_VALUE];

		GLSplrState*			splr_ptrs[QGSGTEX_MAX_VALUE];
		GLTexture*				tex_ptrs[QGSGTEX_MAX_VALUE];

		GLTexture*				off_ptrs[QGSGOFF_MAX_VALUE];

		GLShader*				shd_ptr;
		GLLayout*				los_ptr;

		GLBuffer*				ib_ptr;
		GLBuffer*				vb_ptrs[QGGL_MAX_DRAWLAYOUT_ATTRIB];

		kuint					pup_tpg;
		kuint					pup_vert_count;
		kuint					pup_index_stride;
		
		kuint					pup_vert_stride;
		kuint					pup_vert_size;
		kuint					pup_index_size;
		kpointer				pup_ptr_vert;
		kpointer				pup_ptr_index;

		bool					pup_glyph;

		Pending()
		{
		}
	};

	//
	struct Extp
	{
		qgTexture*				tx_white;
		qgShader*				sp_ortho;
		qgShader*				sp_proj;
		qgShader*				sp_glyph;
		qgVertexLayout*			vl_p4_color;
		qgVertexLayout*			vl_p3_t2_color;
	};

private:
#if QG_OPENGL_ES2
	EGLDisplay				_display;
	EGLSurface				_surface;
	EGLContext				_context;
#elif _SB_WINDOWS_ && !_QG_USE_SDL
	HDC						_hdc;
	HGLRC					_hrc;
	PIXELFORMATDESCRIPTOR	_pfd;
#elif _SB_APPLE_
#error fix me
#elif !_QG_USE_SDL
	GLXDrawable				_drawable;
	Display*				_display;
#endif

	Extp					_extp;
	Session					_sion;
	Pending					_pend;

private:
	GLRdh();
	~GLRdh();

public:
	K_OVR bool Layout(kint width, kint height);
	K_OVR void Reset();

	K_OVR bool Enter(kint clearance);
	K_OVR bool Leave();
	K_OVR bool Flush();

	K_OVR void ClearMRTs(kint clearance, kint colorcount, const tpl::ColorValue* colors, float depth, kuint stencil);

	K_OVR void SetViewport(kint x, kint y, kint w, kint h, float minz, float maxz);
	K_OVR void SetScissor(bool enable, const tpl::Rect& area);

	K_OVR void SetDhslState(qgDhslState* dhsl);
	K_OVR void SetRaszState(qgRaszState* rasz);
	K_OVR void SetBlndState(qgBlndState* blnd);
	K_OVR void SetSplrState(kint stage, qgSplrState* splr);

	K_OVR void SetShader(qgShader* shd, qgVertexLayout* lo);
	K_OVR void SetBufferVertex(kint stage, qgBuffer* buf);
	K_OVR void SetBufferIndex(qgBuffer* buf);

	K_OVR void SetTexture(kint stage, qgTexture* tex);
	K_OVR void SetRenderTargets(kint count, qgTexture** tex);

	K_OVR void Draw(qgTopology tpg, kint verts);
	K_OVR void DrawIndexed(qgTopology tpg, kint indices);

	K_OVR void DrawSprite(const tpl::Rect& bound, const tpl::ColorValue& color, qgTexture* tex, const tpl::Quad* coord);

	K_OVR void DrawLines(bool ortho, bool strip, kint count, const tpl::Vec3* pts, const tpl::ColorValue* colors);
	K_OVR void DrawStrips(bool ortho, kint count, const tpl::Vec3* pts, const tpl::ColorValue* colors, qgTexture* tex, const tpl::Vec2* coords);

	K_OVR void PrimitiveBegin(qgTopology tpg, kint verts, kint stride, kpointer* data);
	K_OVR void PrimitiveEnd();
	K_OVR void PrimitiveBeginIndexed(qgTopology tpg, kint verts, kint vertstride, kpointer* vertdata, kint indices, kint indstride, kpointer* inddata);
	K_OVR void PrimitiveEndIndexed();

	K_OVR void GlyphBegin(qgShader* shd);
	K_OVR void GlyphDraw(kint x, kint y, kint w, kint h, const tpl::ColorValue& color, qgTexture* tex);
	K_OVR void GlyphEnd();

protected:
	K_OVR bool _Initialize(qgStub* stub, kint flags);
	K_OVR bool _ResetPrepare(const tpl::Point& size, bool prepare);
	K_OVR void _Finalize();

protected:
	K_OVR qgResObj* _RoamInitDhslState(const qbDhslInitializer& inz);
	K_OVR qgResObj* _RoamInitRaszState(const qbRaszInitializer& inz);
	K_OVR qgResObj* _RoamInitBlndState(const qbBlndInitializer& inz);
	K_OVR qgResObj* _RoamInitSplrState(const qbSplrInitializer& inz);
	K_OVR qgResObj* _RoamInitShader(const char* name);
	K_OVR qgResObj* _RoamInitVertexLayout(const qbLayoutArray& inz);
	K_OVR qgResObj* _RoamInitBuffer(kint type, kint stride, kint size, kint flags, kconstpointer data);
	K_OVR qgResObj* _RoamInitTexture(const char* name, kint type, kint fmt, kuint width, kuint height, kuint depth, kuint mips, kint flags, qgImage* img);
	K_OVR qgResObj* _RoamInitMotionTexture(const char* filename, kint flags);
	K_OVR qgResObj* _RoamInitDepthBuffer(kuint width, kuint height);

public:
	void CheckBindBuffer(GLenum type, GLuint id) throw();
	void CheckActiveTexture(kint stage) throw();
	void CheckBindTexture(kint stage, GLenum type, GLuint id, GLint miplvl = 0, GLint mipcnt = 0) throw();

private:
#if QG_OPENGL_ES2
	bool _EsReInit(qgStub* stub) throw();
	void _EsTerminate() throw();
#endif

	void _CommitRaszState() throw();
	void _CommitBlndState() throw();
	void _CommitDhslState() throw();
	void _CommitSplrState(kint stage, GLSplrState* splr, GLTexture* tex) throw();
	void _CommitTexture(kint stage, GLTexture* tex) throw();
	void _CommitShader() throw();
	void _CommitDrawLayout() throw();
	void _CommitDrawLayoutUp(kpointer buffer, kuint stride) throw();

	void _ProcessShaderMap() throw();
	void _ProcessTextureStage(kint maxtexs) throw();

	void _InternalClear(kint clearance, const tpl::Color& color, kint stencil, float depth) throw();
	void _InternalDraw(qgTopology tpg, kint texcount, kint vertexcount, kint vertexstart) throw();
	void _InternalDrawIndexed(qgTopology tpg, kint texcount, kint indexcount, kint vertexstart) throw();

	bool _InitializeExtension();
};

#endif	// __INC_QGDRV_GL_RDH_H__
